package de.sendorian.app.forumArchive.domain;

import static de.sendorian.util.StringUtils.TEXT_WIDTH;
import static de.sendorian.util.StringUtils.box;
import static de.sendorian.util.StringUtils.boxCentered;
import static de.sendorian.util.StringUtils.boxMultiline;
import static org.apache.commons.lang.StringUtils.abbreviate;
import static org.apache.commons.lang.StringUtils.remove;

import java.text.DateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinTable;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;

import org.apache.commons.lang.StringUtils;
import org.hibernate.annotations.Cascade;
import org.hibernate.annotations.Fetch;
import org.hibernate.annotations.FetchMode;


@Entity
public class Post {

    @Id
    @GeneratedValue
    private int id;

    @ManyToOne
    private User author;

    @Column(length = 4000)
    private String message;
    
    @Column(length = 200)
    private String footer;

    private Date postDate;
    
    private Date lastEditedDate;

    @OneToMany(cascade = CascadeType.ALL)
    @Cascade(value = org.hibernate.annotations.CascadeType.DELETE_ORPHAN)
    @JoinTable(name = "POST_IMAGES")
    @Fetch(FetchMode.SUBSELECT)
    private List<Image> images = new ArrayList<Image>();

    @OneToMany(cascade = CascadeType.ALL)
    @Cascade(value = org.hibernate.annotations.CascadeType.DELETE_ORPHAN)
    @JoinTable(name = "POST_ARCHIVES")
    @Fetch(FetchMode.SUBSELECT)
    private List<Archive> archives = new ArrayList<Archive>();

    @OneToMany(cascade = CascadeType.ALL)
    @Cascade(value = org.hibernate.annotations.CascadeType.DELETE_ORPHAN)
    @JoinTable(name = "POST_LINKS")
    @Fetch(FetchMode.SUBSELECT)
    private List<Link> links = new ArrayList<Link>();


    public int getId() {
        return id;
    }


    public User getAuthor() {
        return author;
    }


    public void setAuthor(User author) {
        this.author = author;
    }


    public String getMessage() {
        return message;
    }


    public void setMessage(String message) {
        this.message = message;
    }


    public String getFooter() {
        return footer;
    }


    public void setFooter(String footer) {
        this.footer = footer;
    }


    public Date getPostDate() {
        return postDate;
    }


    public void setPostDate(Date postDate) {
        this.postDate = postDate;
    }


    public Date getLastEditedDate() {
        return lastEditedDate;
    }


    public void setLastEditedDate(Date lastEditedDate) {
        this.lastEditedDate = lastEditedDate;
    }


    public List<Image> getImages() {
        return images;
    }


    public void setImages(List<Image> images) {
        this.images = images;
    }


    public List<Archive> getArchives() {
        return archives;
    }


    public void setArchives(List<Archive> archives) {
        this.archives = archives;
    }


    public List<Link> getLinks() {
        return links;
    }


    public void setLinks(List<Link> links) {
        this.links = links;
    }


    @Override
    public String toString() {
        String postDate = this.postDate != null ? " on " + DateFormat.getDateTimeInstance().format(this.postDate)
                : "";
        int imageCount = images != null ? images.size() : 0;
        int archiveCount = archives != null ? archives.size() : 0;
        int externalLinkcount = links != null ? links.size() : 0;
        return "Post by " + author + postDate + " with " + imageCount + " images, " + archiveCount + " archives and "
        + externalLinkcount + " links: " + abbreviate(remove(message, "\n"), 80);
    }


    public String toStringFormatted() {
        int imageCount = images != null ? images.size() : 0;
        int archiveCount = archives != null ? archives.size() : 0;

        StringBuilder builder = new StringBuilder();
        builder.append(LINE);
        builder.append(boxCentered("Post by " + getAuthor() + " on "
                + DateFormat.getDateTimeInstance().format(postDate)));
        builder.append(LINE);
        
        builder.append(boxMultiline(getMessage()));
        String footer = getFooter();
        if (footer != null) {
            builder.append(FOOTER_LINE);
            builder.append(boxMultiline(footer));
        }
        
        builder.append(LINE);
        if (imageCount > 0 || archiveCount > 0) {
            builder.append(boxCentered("With " + imageCount + " images and " + archiveCount + " archives."));
            if (imageCount > 0) {
                for (File image : images) {
                    builder.append(box(" * " + image.getName()));
                }
            }
        } else {
            builder.append(boxCentered("Has no files."));
        }
        builder.append(LINE);
        builder.append("\n");
        return builder.toString();
    }
    

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((author == null) ? 0 : author.hashCode());
        result = prime * result + ((lastEditedDate == null) ? 0 : lastEditedDate.hashCode());
        result = prime * result + ((postDate == null) ? 0 : postDate.hashCode());
        return result;
    }
    

    /**
     * Posts are equal if author, postDate and lastEditedDate are equal.
     */
    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Post other = (Post) obj;
        if (author == null) {
            if (other.author != null)
                return false;
        } else if (!author.equals(other.author))
            return false;
        if (lastEditedDate == null) {
            if (other.lastEditedDate != null)
                return false;
        } else if (!lastEditedDate.equals(other.lastEditedDate))
            return false;
        if (postDate == null) {
            if (other.postDate != null)
                return false;
        } else if (!postDate.equals(other.postDate))
            return false;
        return true;
    }

    private final static String LINE = box(StringUtils.repeat("_", TEXT_WIDTH));
    private final static String FOOTER_LINE = box(StringUtils.repeat("_", 18));
}
